﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Runtime.Serialization;
using System;
using System.Threading;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.Text;
using BrainTechLLC.ThreadSafeObjects;
using System.ComponentModel;
using System.IO;
using Mud.EmlenMudMain;
using System.Diagnostics;

namespace BrainTechLLC
{
    [Serializable]
    public class MobPrototype : MobPrototypeData
    {
        public GameCharTemplate ToCharTemplate()
        {
            GameCharTemplate result = new GameCharTemplate()
            {
                AreaName = this.areastringI,
                Name = new NameAndDescription()
                {
                    Description = this.long_descr,
                    OneLineDescription = this.description,
                    Keywords = this.mobprototypenameI,
                    Name = this.short_descrI,
                    ShortDescription = this.short_descrI
                },
                FriendlyName = string.IsNullOrEmpty(this.mobprototypenameI) ? this.short_descrI : this.mobprototypenameI,
                _typeName = "BrainTechLLC.GameChar"
            };
            if (this.alignment != 0)
                result.AddOrSetProperty("Alignment", this.alignment);
            if (this.armcls != 0)
                result.AddOrSetProperty("ArmorClass", this.armcls);
            if (!string.IsNullOrEmpty(this.attackName))
                result.AddOrSetProperty("AttackName", this.attackName);
            if (this.attackRaces != 0)
                result.AddOrSetProperty("AttackRaces", this.attackRaces);
            if (this.castPercent != 0)
                result.AddOrSetProperty("CastPercent", this.castPercent);
            if (this.castSpells != null && this.castSpells.Count > 0)
                result.AddOrSetProperty("CastSpells", this.castSpells);
            if (commandNameSpecialFunctions != null && commandNameSpecialFunctions.Count > 0)
                result.AddOrSetProperty("SpecialFunctions", this.commandNameSpecialFunctions);
            if (this.extraDamageroll != 0)
                result.AddOrSetProperty("ExtraDamageRoll", this.extraDamageroll);
            if (this.extraDodgeBonus != 0)
                result.AddOrSetProperty("ExtraDodgeBonus", this.extraDodgeBonus);
            if (this.extraHitroll != 0)
                result.AddOrSetProperty("ExtraHitRoll", this.extraHitroll);
            if (this.extraParryBonus != 0)
                result.AddOrSetProperty("ExtraParryBonus", this.extraParryBonus);
            if (this.flurries != 0)
                result.AddOrSetProperty("Flurries", this.flurries);
            if (!string.IsNullOrEmpty(this.guardClan))
                result.AddOrSetProperty("GuardClan", this.guardClan);
            if (!string.IsNullOrEmpty(this.guardSect))
                result.AddOrSetProperty("GuardSect", this.guardSect);
            if (this.height != 0)
                result.AddOrSetProperty("Height", this.height);
            if (this.hpmult != 0)
                result.AddOrSetProperty("HitPointMultiplier", this.hpmult);
            if (this.kicks != 0)
                result.AddOrSetProperty("Kicks", this.kicks);
            result.AddOrSetProperty("Level", this.level);
            if (this.maxInWorld != 0)
                result.AddOrSetProperty("MaxInWorld", this.maxInWorld);
            if (this.mobGuards != 0)
                result.AddOrSetProperty("Guards", this.mobGuards);
            result.AddOrSetProperty("MobType", this.mobtype);
            if (this.money != 0)
                result.AddOrSetProperty("Money", this.money);
            result.AddOrSetProperty("MovementSpeed", this.movementSpeed);
            if (this.objCreationPoints != 0)
                result.AddOrSetProperty("ObjectCreationPoints", this.objCreationPoints);
            result.AddOrSetProperty("Behaviors", this.prototypeBehaviors);
            result.AddOrSetProperty("Effects", this.prototypeEffects);
            result.AddOrSetProperty("RaceName", this.raceName);
            if (this.pShop != null)
            {
                Shop shop = this.pShop.ToShop();
                result.ShopDataId = shop.AssociatedID;
            }
            if (this.random_pop_obj_vnumsI != null && this.random_pop_obj_vnums.Count > 0)
                result.AddOrSetProperty("RandomPopObjectVnums", this.random_pop_obj_vnumsI);
            if (!string.IsNullOrEmpty(this.script_fn))
                result.AddOrSetProperty("Script", this.script_fn);
            result.AddOrSetProperty("Sex", this.sex);
            if (this.skltaught != null && this.skltaught.Count > 0)
                result.AddOrSetProperty("SkillsTaught", this.skltaught);
            if (this.tackles != 0)
                result.AddOrSetProperty("Tackles", this.tackles);
            if (this.timer != 0)
                result.AddOrSetProperty("Timer", this.timer);
            if (this.triggers != null && this.triggers.Count > 0)
                result.AddOrSetProperty("Triggers", this.triggers);
            if (this.vnumAltersInto != 0)
                result.AddOrSetProperty("AltersInto", this.vnumAltersInto);
            if (this.warriorPercent != 0)
                result.AddOrSetProperty("WarriorPercent", this.warriorPercent);
            result.AddOrSetProperty("Vnum", this.vnumI);
            if (this.will_help != 0)
                result.AddOrSetProperty("WillHelp", this.will_help);
            if (this.yeller_number != 0)
                result.AddOrSetProperty("YellerNumber", this.yeller_number);

            result.Register();
            return result;
        }
        public MobPrototype() { }

        [NonSerialized]
        private AreaData areaInternal = null;		/* The area this mob saves in */

        public AreaData AreaInternal
        {
            get { return areaInternal; }
            set { areaInternal = value; }
        }

        public AreaData area
        {
            set
            {
                areaInternal = value;
                Areastring = value.ShortName;// Getstring;
            }
            get
            {
                //if (areaInternal == null)
                //{
                //    for (int i = 0; i < WorldTemplates.AllAreas.Count; i++)
                //    {
                //        AreaData ad = (AreaData)WorldTemplates.AllAreas[i];

                //        if (ad.ShortName.Equals(Areastring) == true)
                //        {
                //            areaInternal = ad;
                //            break;
                //        }
                //    }
                //}
                return areaInternal;
            }
        }

        public void ReadOldMobileFormat(StreamReader sr, int vnum, AreaData area)
        {
            MobPrototype pMobIndex = new MobPrototype();
            pMobIndex.ObjCreationPoints = 0;
            pMobIndex.Vnum = vnum;
            pMobIndex.area = area;
            pMobIndex.AttackName = "";
            pMobIndex.Mobprototypename = "";
            pMobIndex.Short_descr = "";
            pMobIndex.Long_descr = "";
            pMobIndex.Description = "";
            pMobIndex.Script_fn = "";
            pMobIndex.Mobtype = MobTypes.HUMAN;
            pMobIndex.GuardClan = "";
            pMobIndex.GuardSect = "";
            pMobIndex.Hpmult = 10;
            pMobIndex.Yeller_number = 0;
            pMobIndex.MaxInWorld = 5;
            pMobIndex.Height = -1;
            pMobIndex.MobGuards = -1;
            pMobIndex.PrototypeBehaviors = 0;

            pMobIndex.PrototypeEffects = 0;
            pMobIndex.Alignment = 0;
            pMobIndex.Money = 0;
            pMobIndex.Sex = 0;

            pMobIndex.Armcls = 101;
            pMobIndex.AttackRaces = 0;
            pMobIndex.VnumAltersInto = 0;
            pMobIndex.MobGuards = -1;
            pMobIndex.ExtraHitroll = 0;
            pMobIndex.ExtraDamageroll = 0;
            pMobIndex.ExtraDodgeBonus = 0;
            pMobIndex.ExtraParryBonus = 0;
            char[] spc = new char[1];
            spc[0] = ' ';

            while (sr.EndOfStream == false)
            {
                string szLine = sr.ReadLine().Trim();
                string[] rgsz = szLine.Split(spc, 2, StringSplitOptions.RemoveEmptyEntries);

                if (szLine == "End")
                {
                    if (pMobIndex.Mobprototypename == "")
                        pMobIndex.Mobprototypename = "(no name)";
                    if (pMobIndex.Short_descr == "")
                        pMobIndex.Short_descr = "(no short desc)";
                    if (pMobIndex.Long_descr == "")
                        pMobIndex.Long_descr = "(no long desc)\n\r";
                    if (pMobIndex.Description == "")
                        pMobIndex.Description = "(no description)";
                    area.MobPrototypesBelongingToArea.Add(pMobIndex);
                    return;
                }

                string szWord = rgsz[0];

                if (szWord == "Attackmsg")
                {
                    pMobIndex.AttackName = rgsz[1].TrimEnd('~');
                    continue;
                }
                if (szWord == "AClan2") { pMobIndex.GuardSect = rgsz[1]; continue; }
                if (szWord == "AClan") { pMobIndex.GuardClan = rgsz[1]; continue; }
                if (szWord == "ActBits") { pMobIndex.PrototypeBehaviors = (ActionsAndBehavior)Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "ActBits3")
                {
                    Int64 tmp = (Convert.ToInt64(rgsz[1]) << 32);
                    pMobIndex.PrototypeBehaviors |= (ActionsAndBehavior)tmp;
                    continue;
                }
                if (szWord == "AYeller") { pMobIndex.Yeller_number = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "AMax") { pMobIndex.MaxInWorld = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "AWillhelp") { pMobIndex.Will_help = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "ActBits4")
                {
                    int tmp = (Convert.ToInt32(rgsz[1]));
                    if ((tmp & 0x00000800) != 0)
                    { // MOBSWITCH
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.MOBSWITCH;
                    }
                    if ((tmp & 0x00001000) != 0)
                    { // FASTHUNT
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.FASTHUNT;
                    }
                    if ((tmp & 0x00002000) != 0)
                    { // SOLOYELL 
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.SOLOYELL;
                    }
                    if ((tmp & 0x00004000) != 0)
                    { // STAYOFFROAD 
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.STAYOFFROAD;
                    }
                    if ((tmp & 0x00008000) != 0)
                    { // KILLALLONE
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.KILLALLONE;
                    }
                    if ((tmp & 0x00010000) != 0)
                    { // KILLALLTWO
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.KILLALLTWO;
                    }
                    if ((tmp & 0x00020000) != 0)
                    { // KILLMEVIL
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.KILLMEVIL;
                    }
                    if ((tmp & 0x00040000) != 0)
                    { // KILLMGOOD 
                        pMobIndex.PrototypeBehaviors |= ActionsAndBehavior.KILLMGOOD;
                    }
                    continue;
                }
                if (szWord == "Affect_By") { pMobIndex.PrototypeEffects = (long)Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "AffectTWO")
                {
                    Int64 i64 = Convert.ToInt64(rgsz[1]);
                    Int64 i64Shifted = i64 << 32;
                    //pMobIndex.more_affected_by = (EffectType2) 
                    pMobIndex.PrototypeEffects |= (long)i64Shifted;
                    continue;
                }
                if (szWord == "Alignment") { pMobIndex.Alignment = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Alt_vnum") { pMobIndex.VnumAltersInto = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "ArmorClass") { pMobIndex.Armcls = Convert.ToInt32(rgsz[1]); continue; }

                if (szWord == "ASklTaught")
                {
                    string[] rgSpl2 = rgsz[1].Split(spc, 2, StringSplitOptions.RemoveEmptyEntries);
                    int num = Convert.ToInt32(rgSpl2[0]);
                    int num2 = Convert.ToInt32(rgSpl2[1]);
                    if (num != 30) pMobIndex.Skltaught.Add(num2, num);
                    continue;
                }

                if (szWord == "BCasts")
                {
                    pMobIndex.CastSpells.Add(rgsz[1].TrimEnd('~'));
                    continue;
                }
                if (szWord == "BCast_P")
                {
                    pMobIndex.CastPercent = Convert.ToInt32(rgsz[1]);
                    continue;
                }
                if (szWord == "BKicks")
                {
                    pMobIndex.Kicks = Convert.ToInt32(rgsz[1]);
                    continue;
                }
                if (szWord == "BFlurries")
                {
                    pMobIndex.Flurries = Convert.ToInt32(rgsz[1]);
                    continue;
                }
                if (szWord == "BTackles")
                {
                    pMobIndex.Tackles = Convert.ToInt32(rgsz[1]);
                    continue;
                }
                if (szWord == "BWarrior_P")
                {
                    pMobIndex.WarriorPercent = Convert.ToInt32(rgsz[1]);
                    continue;
                }

                if (szWord == "Guard") { pMobIndex.MobGuards = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "GHitR") { pMobIndex.ExtraHitroll = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "GDamR") { pMobIndex.ExtraDamageroll = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "GDod") { pMobIndex.ExtraDodgeBonus = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "GPar") { pMobIndex.ExtraParryBonus = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Hp") { pMobIndex.Hpmult = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "JPts") { pMobIndex.ObjCreationPoints = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "JavO") { continue; } //pMobIndex.objImage[0] = (char)Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "JavT") { continue; } // pMobIndex.objImage[1] = (char)Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "MobType") { pMobIndex.Mobtype = (MobTypes)Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Money") { pMobIndex.Money = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "NHeight") { pMobIndex.Height = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Shopd2") { pMobIndex.PShop.Decrease = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Shopd3") { pMobIndex.PShop.Items_until_decrease = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "ShopCr") { pMobIndex.PShop.Creates_vnum = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "ShCrh") { pMobIndex.PShop.Creates_hours = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "RaceHate") { pMobIndex.AttackRaces = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Sex") { pMobIndex.Sex = (Sex)Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Name") { pMobIndex.Mobprototypename = rgsz[1].TrimEnd('~'); continue; }
                if (szWord == "Short") { pMobIndex.Short_descr = rgsz[1].TrimEnd('~'); continue; }
                if (szWord == "Level") { pMobIndex.Level = Convert.ToInt32(rgsz[1]); continue; }
                if (szWord == "Spec") // NYI HEREHERE
                {
                    pMobIndex.Spec_fun = rgsz[1].TrimEnd('~');
                    continue;
                }
                if (szWord == "ShopCS") { pMobIndex.PShop.Creates_message = rgsz[1].TrimEnd('~'); continue; }
                if (szWord == "Shop")
                {
                    // TODO
                    //ShopData pShop = new ShopData(EmlenMud);
                    //pShop.Keeper = vnum;
                    //string[] rgSpl4 = rgsz[1].Split(spc, StringSplitOptions.RemoveEmptyEntries);
                    //for (int iTrade = 0; iTrade < 5; iTrade++)
                    //    pShop.Buy_type.Add(Convert.ToInt32(rgSpl4[iTrade]));

                    //pShop.Profit_buy = Convert.ToInt32(rgSpl4[5]);
                    //pShop.Profit_sell = Convert.ToInt32(rgSpl4[6]);
                    //pShop.Creates_hours = 1;
                    //pShop.Open_hour = Convert.ToInt32(rgSpl4[7]);
                    //pShop.Close_hour = Convert.ToInt32(rgSpl4[8]);
                    //pShop.Decrease = 5;
                    //pShop.Items_until_decrease = 4;
                    //pShop.Creates_vnum = 0;
                    //pShop.Creates_message = "";
                    //pMobIndex.PShop = pShop;

                    continue;
                }

                if (szWord == "SFT")
                {
                    pMobIndex.script_fn = rgsz[1].TrimEnd('~');
                    continue;
                }

                if (szWord == "Long")
                {
                    StringBuilder sb = new StringBuilder(1024);

                    string szLine2 = sr.ReadLine();
                    while (szLine2.Trim() != "~")
                    {
                        sb.AppendLine(szLine2);
                        szLine2 = sr.ReadLine();
                    }
                    pMobIndex.Long_descr = sb.ToString();
                    continue;
                }


                if (szWord == "Descr")
                {
                    pMobIndex.Description = "";
                    string szLine2 = sr.ReadLine();
                    while (szLine2.Trim() != "~")
                    {
                        pMobIndex.Description += szLine2 + "\n\r";
                        szLine2 = sr.ReadLine();
                    }
                    continue;
                }
            }
            return;
        }

        public void WriteOldMobileFormat(StreamWriter sw, int vnum, MobPrototype mp, AreaData area)
        {
            MobPrototype pMobIndex = (MobPrototype)mp;
            char[] spc = new char[1];
            spc[0] = ' ';
            sw.WriteLine("#" + vnum.ToString());

            sw.WriteLine("Attackmsg " + pMobIndex.AttackName + "~");
            if (!string.IsNullOrEmpty(pMobIndex.GuardSect))
                sw.WriteLine("AClan2 " + pMobIndex.GuardSect);
            if (!string.IsNullOrEmpty(pMobIndex.GuardClan))
                sw.WriteLine("AClan " + pMobIndex.GuardClan);

            Int64 i64 = (Int64)pMobIndex.PrototypeBehaviors;
            Int64 actbits = ((i64 << 32) >> 32);
            Int64 actbits3 = (i64 >> 32);
            sw.WriteLine("ActBits " + actbits.ToString());
            sw.WriteLine("ActBits3 " + actbits3.ToString());
            sw.WriteLine("AYeller " + pMobIndex.Yeller_number.ToString());
            sw.WriteLine("AMax " + pMobIndex.MaxInWorld.ToString());
            sw.WriteLine("AWillhelp " + pMobIndex.Will_help.ToString());

            int actbits4 = 0;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.MOBSWITCH) != 0)
                actbits4 |= 0x00000800;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.FASTHUNT) != 0)
                actbits4 |= 0x00001000;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.SOLOYELL) != 0)
                actbits4 |= 0x00002000;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.STAYOFFROAD) != 0)
                actbits4 |= 0x00004000;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.KILLALLONE) != 0)
                actbits4 |= 0x00008000;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.KILLALLTWO) != 0)
                actbits4 |= 0x00010000;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.KILLMEVIL) != 0)
                actbits4 |= 0x00020000;
            if ((pMobIndex.PrototypeBehaviors & ActionsAndBehavior.KILLMGOOD) != 0)
                actbits4 |= 0x00040000;
            sw.WriteLine("ActBits4 " + actbits4.ToString());

            Int64 aff1 = ((((Int64)pMobIndex.PrototypeEffects) << 32) >> 32);
            Int64 aff2 = (((Int64)pMobIndex.PrototypeEffects) >> 32);
            sw.WriteLine("Affect_By " + aff1.ToString());
            sw.WriteLine("AffectTWO " + aff2.ToString());

            sw.WriteLine("Alignment " + pMobIndex.Alignment.ToString());
            sw.WriteLine("Alt_vnum " + pMobIndex.VnumAltersInto.ToString());
            sw.WriteLine("ArmorClass " + pMobIndex.Armcls.ToString());
            int nSkl = 0;
            foreach (var de in pMobIndex.Skltaught)
            {
                sw.WriteLine("ASkltTaught " + nSkl.ToString() + " " + de.Value.ToString());
                nSkl++;
            }
            if (pMobIndex.CastSpells.Count > 0)
            {
                sw.WriteLine("BCasts " + pMobIndex.CastSpells[0].ToString() + "~");
                sw.WriteLine("BCast_P " + pMobIndex.CastPercent.ToString());
            }
            if (pMobIndex.Kicks > 0) sw.WriteLine("BKicks " + pMobIndex.Kicks.ToString());
            if (pMobIndex.Flurries > 0) sw.WriteLine("BFlurries " + pMobIndex.Flurries.ToString());
            if (pMobIndex.Tackles > 0) sw.WriteLine("BTackles " + pMobIndex.Tackles.ToString());
            if (pMobIndex.WarriorPercent > 0) sw.WriteLine("BWarrior_P " + pMobIndex.WarriorPercent.ToString());
            if (pMobIndex.MobGuards > 0) sw.WriteLine("Guard " + pMobIndex.MobGuards.ToString());
            if (pMobIndex.ExtraHitroll != 0) sw.WriteLine("GHitR " + pMobIndex.ExtraHitroll.ToString());
            if (pMobIndex.ExtraDamageroll != 0) sw.WriteLine("GDamR " + pMobIndex.ExtraDamageroll.ToString());
            if (pMobIndex.ExtraDodgeBonus != 0) sw.WriteLine("GDod " + pMobIndex.ExtraDodgeBonus.ToString());
            if (pMobIndex.ExtraParryBonus != 0) sw.WriteLine("GPar " + pMobIndex.ExtraParryBonus.ToString());
            if (pMobIndex.Hpmult != 0) sw.WriteLine("Hp " + pMobIndex.Hpmult.ToString());
            if (pMobIndex.ObjCreationPoints != 0) sw.WriteLine("JPts " + pMobIndex.ObjCreationPoints.ToString());
            if (pMobIndex.Mobtype != 0) sw.WriteLine("MobType " + ((int)pMobIndex.Mobtype).ToString());
            if (pMobIndex.Money != 0) sw.WriteLine("Money " + pMobIndex.Money.ToString());
            if (pMobIndex.Height != 0) sw.WriteLine("NHeight " + pMobIndex.Height.ToString());
            if (pMobIndex.PShop != null)
            {
                sw.Write("Shop " + pMobIndex.PShop.Keeper.ToString());

                for (int iTrade = 0; iTrade < 5; iTrade++)
                {
                    if (pMobIndex.PShop.Buy_type.Count > iTrade)
                    {
                        sw.Write(" " + pMobIndex.PShop.Buy_type[iTrade].ToString());
                    }
                    else
                    {
                        sw.Write(" 0");
                    }
                }

                sw.Write(" " + pMobIndex.PShop.Profit_buy.ToString());
                sw.Write(" " + pMobIndex.PShop.Profit_sell.ToString());
                sw.Write(" " + pMobIndex.PShop.Open_hour.ToString());
                sw.WriteLine(" " + pMobIndex.PShop.Close_hour.ToString());

                sw.WriteLine("Shopd2 " + pMobIndex.PShop.Decrease.ToString());
                sw.WriteLine("Shopd3 " + pMobIndex.PShop.Items_until_decrease.ToString());
                sw.WriteLine("ShopCr " + pMobIndex.PShop.Creates_vnum.ToString());
                sw.WriteLine("ShCrh " + pMobIndex.PShop.Creates_hours.ToString());
                if (!string.IsNullOrEmpty(pMobIndex.PShop.Creates_message))
                    sw.WriteLine("ShopCS " + pMobIndex.PShop.Creates_message + "~");

            }

            sw.WriteLine("RaceHate " + pMobIndex.AttackRaces.ToString());
            sw.WriteLine("Sex " + ((int)pMobIndex.Sex).ToString());
            sw.WriteLine("Name " + pMobIndex.Mobprototypename.ToString() + "~");
            sw.WriteLine("Short " + pMobIndex.Short_descr.ToString() + "~");
            sw.WriteLine("Level " + pMobIndex.Level.ToString());

            if (!string.IsNullOrEmpty(pMobIndex.Spec_fun))
                sw.WriteLine("Spec " + pMobIndex.Spec_fun);

            if (!string.IsNullOrEmpty(pMobIndex.Script_fn))
                sw.WriteLine("SFT " + pMobIndex.Script_fn);

            sw.WriteLine("Long");
            sw.WriteLine(pMobIndex.Long_descr);
            sw.WriteLine("~");

            sw.WriteLine("Descr");
            sw.WriteLine(pMobIndex.Description);
            sw.WriteLine("~");

            sw.WriteLine("End");
            sw.WriteLine("");
        }


        public void save_mobiles_old_format(StreamWriter sw, AreaData area)
        {
            for (int n = 0; n < area.MobPrototypesBelongingToArea.Count; n++)
            {
                MobPrototype mp = (MobPrototype)area.MobPrototypesBelongingToArea[n];
                sw.WriteLine("#" + mp.Vnum.ToString());
                WriteOldMobileFormat(sw, mp.Vnum, mp, area);
            }
        }

        // something about saving the mobs isn't working
        public void load_mobiles_old_format(StreamReader sr, AreaData area)
        {
            area.TotalMobPrototypes = 0;
            while (sr.EndOfStream == false)
            {
                int vnum;
                char c = ' ';
                while (c != '#' && sr.EndOfStream == false) c = (char)sr.Read();
                if (c != '#')
                {
                    Debug.WriteLine("Area " + area.ShortName + " possibly corrupt?  No # on the load_mobiles section...");
                    EmlenMud.LogError("Area " + area.ShortName + " possibly corrupt?  No # on the load_mobiles section...", null, LogType.WorldError);
                    break;
                }

                vnum = Convert.ToInt32(sr.ReadLine().Trim());
                if (vnum == 0) break;
                if (EmlenMud.WorldTemplates.AllMobPrototypes.ContainsKey(vnum) == true)
                {
                    EmlenMud.LogError("Load_mobiles: vnum " + vnum.ToString() + " duplicated in area " + area.ShortName, null, LogType.WorldError);
                    continue;
                }

                ReadOldMobileFormat(sr, vnum, area);
                area.TotalMobPrototypes++;
                if (vnum > EmlenMud.WorldTemplates.top_vnum_mob_prototype) EmlenMud.WorldTemplates.top_vnum_mob_prototype = vnum;
            }
        }
    }

    [Serializable]
    public class MobPrototypeData : GameThingBaseClass
    {
        public MobPrototypeData() { }

        private string spec_fun = "";

        [DescriptionAttribute("Special function name associated with the mob... need to look up the list..."),
        Category("Behaviors and Effects")]
        public string Spec_fun { get { return spec_fun; } set { spec_fun = value; } }

        // Random pop loading will populate this arraylist
        [NonSerialized]
        public List<long> random_pop_obj_vnumsI = new List<long>();

        public List<long> random_pop_obj_vnums { get { return random_pop_obj_vnumsI; } set { random_pop_obj_vnumsI = value; } }

        public bool HasPrototypeBehavior(ActionsAndBehavior behavior)
        {
            return ((PrototypeBehaviors & behavior) != 0);
        }

        public bool HasPrototypeEffects(EffectType effect)
        {
            return ((PrototypeEffects & (long)effect) != 0);
        }

        public string areastringI;

        [DescriptionAttribute("The name of the area with which this mob is associated"),
        Category("Naming and Reference")]
        public string Areastring
        {
            get { return areastringI; }
            set { areastringI = value; }
        }

        public int vnumI = 0;

        [DescriptionAttribute("The vnum of this mob"),
        Category("Naming and Reference")]
        public int Vnum
        {
            get { return vnumI; }
            set { vnumI = value; }
        }

        public string mobprototypenameI = "";

        [DescriptionAttribute("Keywords used to reference this mob (i.e. 'small stray cat')"),
        Category("Naming and Reference")]
        public string Mobprototypename
        {
            get { return mobprototypenameI; }
            set { mobprototypenameI = value; }
        }

        public string short_descrI = "";

        [DescriptionAttribute("A short description for the mobile, such as 'a giant cow' Note: do not capitalize the first letter unless the mob has a proper noun as a name (i.e. Thor)"),
        Category("Naming and Reference")]
        public string Short_descr
        {
            get { return short_descrI; }
            set { short_descrI = value; }
        }

        public string long_descr = "";

        [DescriptionAttribute("A one-line description of the mobile, shown to the current room when players 'look' (i.e. 'A huge Xylarian guard is here, patrolling the streets.')"),
        Category("Naming and Reference")]
        public string Long_descr
        {
            get { return long_descr; }
            set { long_descr = value; }
        }

        public string description = "";

        [DescriptionAttribute("The full textual description of the mobile (possibly a paragraph long, etc)"),
        Category("Naming and Reference")]
        public string Description
        {
            get { return description; }
            set { description = value; }
        }


        public int maxInWorld = 9999;

        [DescriptionAttribute("Maximum of this mob in the world at once"),
        Category("World Limits")]
        public int MaxInWorld
        {
            get { return maxInWorld; }
            set { maxInWorld = value; }
        }


        public Sex sex = Sex.NEUTRAL;

        [DescriptionAttribute("The sex of the mob (Male/Female/Neutral)"),
        Category("General Mobile Attributes")]
        public Sex Sex
        {
            get { return sex; }
            set { sex = value; }
        }

        public int level = 1;		/* Mob's level */

        [DescriptionAttribute("The mobile's level.  This determines general power of the creature/person, as well as experience and a host of other important factors."),
        Category("General Mobile Attributes")]
        public int Level
        {
            get { return level; }
            set { level = value; }
        }

        public int timer = 0;

        [DescriptionAttribute("This sets for how many *seconds* the mobile will live before it disappears (completely vanishes)"),
        Category("General Mobile Attributes")]
        public int Timer
        {
            get { return timer; }
            set { timer = value; }
        }

        public int alignment = 0;

        [DescriptionAttribute("Alignment of the mobile.  Negative is evil, positive is good."),
        Category("General Mobile Attributes")]
        public int Alignment
        {
            get { return alignment; }
            set { alignment = value; }
        }

        public int money = 0;

        [DescriptionAttribute("Maximum total amount of copper coins (plus or minus a few) the mobile will be carrying when created."),
        Category("General Mobile Attributes")]
        public int Money
        {
            get { return money; }
            set { money = value; }
        }

        public int height = 0;

        [DescriptionAttribute("The height of this mob, or 0 for default height for the mobile/race type"),
        Category("General Mobile Attributes")]
        public int Height
        {
            get { return height; }
            set { height = value; }
        }

        public MobTypes mobtype = MobTypes.NONE;

        [DescriptionAttribute("The Mobile type. This is used to determine attack name (if not overridden), height of the mob, and other general characteristics. If NONE, then racename will be used to determine the mobile's race"),
        Category("General Mobile Attributes")]
        public MobTypes Mobtype
        {
            get { return mobtype; }
            set { mobtype = value; }
        }

        public string raceName = string.Empty;

        [DescriptionAttribute("If the mob is of a player race, this field specifies of which race"),
        Category("General Mobile Attributes")]
        public string RaceName
        {
            get { return raceName; }
            set { raceName = value; }
        }

        public int objCreationPoints = 0;

        [DescriptionAttribute("Points available for object creation (TODO: Look up what this does!)"),
        Category("General Mobile Attributes")]
        public int ObjCreationPoints
        {
            get { return objCreationPoints; }
            set { objCreationPoints = value; }
        }

        public int movementSpeed = 900;

        [DescriptionAttribute("The number of milliseconds it takes the mobile to move one room on standard terrain (default=900)"),
        Category("General Mobile Attributes")]
        public int MovementSpeed
        {
            get { return movementSpeed; }
            set { movementSpeed = value; }
        }


        public ActionsAndBehavior prototypeBehaviors = ActionsAndBehavior.NONE;

        [DescriptionAttribute("ActionsAndBehavior template -- determines the default actions and behaviors of this mobile when it is created"),
        Category("Behaviors and Effects")]
        public ActionsAndBehavior PrototypeBehaviors
        {
            get { return prototypeBehaviors; }
            set { prototypeBehaviors = value; }
        }

        public long prototypeEffects = (long)EffectType.NONE;

        [DescriptionAttribute("When the mobile is created, it will be bestowed with these natural effects (it will be affected by these flags)"),
        Category("Behaviors and Effects")]
        public long PrototypeEffects
        {
            get { return prototypeEffects; }
            set { prototypeEffects = value; }
        }

        public int attackRaces = 0;

        [DescriptionAttribute("Attacks these specific races on sight"),
        Category("Behaviors and Effects")]
        public int AttackRaces
        {
            get { return attackRaces; }
            set { attackRaces = value; }
        }

        public int vnumAltersInto = 0;

        [DescriptionAttribute("Alters into this vnum... currently unused"),
        Category("Behaviors and Effects")]
        public int VnumAltersInto
        {
            get { return vnumAltersInto; }
            set { vnumAltersInto = value; }
        }

        public int mobGuards = 0;

        [DescriptionAttribute("Guards this direction, this mob vnum, or this obj vnum, depends on flags."),
        Category("Behaviors and Effects")]
        public int MobGuards
        {
            get { return mobGuards; }
            set { mobGuards = value; }
        }

        public int yeller_number = 0;

        [DescriptionAttribute("This is a unique number that can be used to match a help-yeller with its helper(s) in the area."),
        Category("Behaviors and Effects")]
        public int Yeller_number
        {
            get { return yeller_number; }
            set { yeller_number = value; }
        }

        public int will_help = 0;

        [DescriptionAttribute("Will this mob set it's rgHunting string to the char name if another mob with the **same yeller_number** in the area recieves a yell_message?"),
        Category("Behaviors and Effects")]
        public int Will_help
        {
            get { return will_help; }
            set { will_help = value; }
        }

        public string guardClan = "";

        [DescriptionAttribute("If set to a nonzero value or a string, the mobile will guards for this clannumber (or clan name)"),
        Category("Behaviors and Effects")]
        public string GuardClan
        {
            get { return guardClan; }
            set { guardClan = value; }
        }

        public string guardSect = "";

        [DescriptionAttribute("If set to a nonzero value or a string, the mobile will guards for this sectnumber (or sect name)"),
        Category("Behaviors and Effects")]
        public string GuardSect
        {
            get { return guardSect; }
            set { guardSect = value; }
        }

        public List<string> castSpells = new List<string>();

        [DescriptionAttribute("Casts this list of spells (in combat if applicable, otherwise, when standing)"),
        Category("Behaviors and Effects")]
        public List<string> CastSpells
        {
            get { return castSpells; }
            set { castSpells = value; }
        }

        public int castPercent = 0;

        [DescriptionAttribute("The percent chance the mobile will cast a spell in a combat round"),
        Category("Behaviors and Effects")]
        public int CastPercent
        {
            get { return castPercent; }
            set { castPercent = value; }
        }


        public string attackName = "";

        [DescriptionAttribute("Attack name, or an empty string for default attack type (i.e. 'claw')"),
        Category("General Combat")]
        public string AttackName
        {
            get { return attackName; }
            set { attackName = value; }
        }

        public int hpmult = 0;

        [DescriptionAttribute("Hit point and experience multiplier.  (TODO: Need to look up how this exactly affects HP and exp)"),
        Category("General Combat")]
        public int Hpmult
        {
            get { return hpmult; }
            set { hpmult = value; }
        }

        public int armcls = 101;

        [DescriptionAttribute("Armor class. 101 = default armor class given the mobile's level"),
        Category("General Combat")]
        public int Armcls
        {
            get { return armcls; }
            set { armcls = value; }
        }


        public int extraHitroll = 0;

        [DescriptionAttribute("Extra Hitroll"),
        Category("General Combat")]
        public int ExtraHitroll
        {
            get { return extraHitroll; }
            set { extraHitroll = value; }
        }


        public int extraDamageroll = 0;

        [DescriptionAttribute("Extra damageRoll.  Can be - or +"),
        Category("General Combat")]
        public int ExtraDamageroll
        {
            get { return extraDamageroll; }
            set { extraDamageroll = value; }
        }

        public int extraDodgeBonus = 0;

        [DescriptionAttribute("Extra Dodge bonus."),
        Category("General Combat")]
        public int ExtraDodgeBonus
        {
            get { return extraDodgeBonus; }
            set { extraDodgeBonus = value; }
        }


        public int extraParryBonus = 0;

        [DescriptionAttribute("Extra Parry bonus, for mobs with weapons only"),
        Category("General Combat")]
        public int ExtraParryBonus
        {
            get { return extraParryBonus; }
            set { extraParryBonus = value; }
        }

        public int kicks = 0;

        [DescriptionAttribute("If nonzero, the percent chance a mob kicks the opponent during a given combat round"),
        Category("General Combat")]
        public int Kicks
        {
            get { return kicks; }
            set { kicks = value; }
        }

        public int tackles = 0;

        [DescriptionAttribute("If nonzero, the percent chance a mob attempts to tackle the opponent during a given combat round"),
        Category("General Combat")]
        public int Tackles
        {
            get { return tackles; }
            set { tackles = value; }
        }


        public int flurries = 0;

        [DescriptionAttribute("If nonzero, the percent chance a mob flurries during a given combat round"),
        Category("General Combat")]
        public int Flurries
        {
            get { return flurries; }
            set { flurries = value; }
        }

        public int warriorPercent = 0;

        [DescriptionAttribute("Percent the mob will try a kick/tackle/flurry"),
        Category("General Combat")]
        public int WarriorPercent
        {
            get { return warriorPercent; }
            set { warriorPercent = value; }
        }

        public ShopData pShop = null;

        [DescriptionAttribute("Shop data attached to mob."),
        Category("Shop and Training")]
        public ShopData PShop
        {
            get { return pShop; }
            set { pShop = value; }
        }
        public Dictionary<long, int> skltaught = new Dictionary<long, int>();

        [DescriptionAttribute("Skills this mob teaches. Key = skill/spell number, Value = old save index?"),
        Category("Shop and Training")]
        public Dictionary<long, int> Skltaught
        {
            get { return skltaught; }
            set { skltaught = value; }
        }

        public List<string> commandNameSpecialFunctions = new List<string>();

        [DescriptionAttribute("A list of textual 'special' commands that the mob executes during combat.  Not yet implemented."),
        Category("Special Functions and Scripts")]
        public List<string> CommandNameSpecialFunctions
        {
            get { return commandNameSpecialFunctions; }
            set { commandNameSpecialFunctions = value; }
        }

        public string script_fn = "";

        [DescriptionAttribute("Script function for the mobile, for old format scripts.  Not yet implemented."),
        Category("Special Functions and Scripts")]
        public string Script_fn
        {
            get { return script_fn; }
            set { script_fn = value; }
        }


        public int mobPicture = 0;

        [DescriptionAttribute("NYI"),
        Category("Appearance and Graphics")]
        public int MobPicture
        {
            get { return mobPicture; }
            set { mobPicture = value; }
        }

        public List<string> triggers = new List<string>();	/* for OLD scripts */
    }


}
